STRING
Autor : Ognjen Radovic '4.1. Dosadne stvari koje morate da shvatite pre nego što uronite' Da li ste znali da ljudi iz Bungavila imaju najmanju azbuku na svetu? Njihov Rotokas azbuka je sastavljena od samo 12 slova: A, E, G, I, K, O, P, R, S, T, U i V. Sa druge strane jezici poput kineskog, japanskog i korejskog imaju hiljade znakova. Engleski, naravno ima 26 slova - 52 ako ubrojite vekaraktera i mala slova odvojeno - plus jos mnogo znakova interpukcije ! @ # $% & Kada ljudi govore o „tekstu“, oni misle na „znakove i simbole na ekranu računara.“ Ali računari ne rade sa znakovima i simbolima; oni rade sa bitovima i bajtovima. Svaki deo teksta koji ste ikada videli na ekranu računara zapravo je smešteno u određen koder znakova. Grubo rečeno Kodiranje znakova omogućava putanju između stvari koje vidite na ekranu i vaše stvari računar se zapravo čuva u memoriji i na disku. Postoji mnogo različitih šifriranja karaktera, neke optimizovani za određene jezike poput ruskog ili kineskog ili engleskog i drugi koji se mogu koristiti na više jezika. U stvarnosti je mnogo složenije od toga. Mnogo znakova je zajedničko za više kodiranja, ali svako kodiranje može koristiti različitu sekvencu bajtova da bi se ti znakovi zapravo spremili u memoriju ili na disk. Tako možete da razmišljate o kodiranju znakova kao o ključu za dešifrovanje. Kad god vam neko da sekvencu bajtova - fajl, veb stranicu... - i tvrdi da je to „tekst“, morate znati koji znak kodiranja su koristili pri kodiranju tako da možete dekodirati bajtove u znakove. Ako vam daju pogrešan ključ ili vam ga ne daju uopšte, na vama je da sami dekodirate kod. Verovatno ćete pogrešiti , i rezultat će biti neispravan 106 Sve što si mislio da znaš o stringovima je pogrešno Sigurno ste naišli na veb stranice poput ove, sa čudnim znakovima u obkarakteru upitnika gde bi apostrofi trebali biti. To uglavnom znači da autor stranice nije podesio ispravno kodiranje znakova, pa je vaš pregledač nagađo, a rezultat je bio kombinacija očekivanih i neočekivanih znakova. Na engleskom je jednostavno samo neugodno; na drugim jezicima, rezultat može biti u potpunosti nečitljiv. Kodiranje znakova postoji za svaki veći jezik u svetu. Pošto se svaki jezik razkarakteruje i memorija i prostor na disku su uvek bili skupi, svako kodiranje znakova optimizovano je za određeno Jezik. Pod tim se misli na svako kodiranje koristi iste brojeve (0–255) koji predstavljaju znakove tog jezika. Na primer, verovatno ste upoznati sa ASCII kodiranje, u kojem se engleska slova čuvaju kao brojevi u rasponu od 0 do 127. (65 je vekaraktero „A“, 97 su mala slova „a“ i c.) Engleski jezik ima vrlo jednostavnu azbuku, pa se može u potpunosti izraziti u manje od 128 brojeva. Za one od vas koji mogu računati u sistemu sa bazom 2, to je 7 od 8 bita u bajtu. Zapadnoevropski jezici poput Francuskog, Španskog i Nemačkog imaju više slova nego engleski. Zapravo imaju slova kombinovana sa različitim dijakritičkim oznakama, poput znaka ñ na španskom. Najviše zastupljeno kodiranje za ove jezike je CP-1252, koji se takođe naziva i „Windows-1252“, jer je široko rasprostranjen na Microsoft Windowsu. CP-1252 kodiranje deli znakove sa ASCII u rasponu 0–127, ali tada širi raspon na 128–255 za znakove poput n-sa-tildom-preko-njega (241), u-sa-dve tačke-iznad-njega (252), & c. To je još uvek jednobajtno kodiranje; najveći mogući broj, 255, još uvek se uklapa u jedan bajt. Zatim postoje jezici poput kineskog, japanskog i korejskog, koji imaju tokaraktero mnogo znakova da i oni zahtevaju višebajtne skupove znakova. Odnosno, svaki „znak“ je predstavljen dvobajtnim brojem od 0–65535. Ali različiti dekoderi sa više bajta i dalje imaju isti problem kao i različiti jednobajtni enkodovi, naime, svaki od njih koristi iste brojeve koji znače različite stvari. Kod njih je samo raspon brojeva širi jer postoji mnogo više karaktera. 107 To je uglavnom bilo u redu u neumreženom svetu, gde je „tekst“ bio nešto što ste upisali i štampali sami. Nije bilo mnogo „čistog teksta“. Izvorni kod je bio ASCII, a svi ostali su upotrebljavali procesore reči, koji su definisali svoje vlastite (ne-tekstualne) formate koji su pratili informaciju o kodiranju znakova sa bogatim stajlingom i c. Ljudi čitaju te dokumente upotrebom istog programa za obradu teksta kao i originalni autore, pa je sve manje-više funkcionisalo, Sada razmislite o usponu globalnih mreža poput e-pošte i interneta. Mnogo "čistog teksta" se koristi , Pisan na jednom računaru, prenosi se preko drugog računara i prima i prikazuje trećim računarom. Računari mogu da vide samo brojeve, ali brojevi mogu značiti različite stvari. O, ne! Šta da se radi? Pa, sistemi su morali da budu dizajnirani da nose informacije kodiranja zajedno sa svakim delom „čistog teksta.“ Ne zaboravite, ključ za dešifrovanje povezuje karaktere razumne računaru i karaktere čitljive čoveku Nedostajući ključ za dešifrovanje znači nečitljiv tekst. Sada razmislite o mogućnosti skladištenja više komada teksta, u istoj tabeli baze podataka koja sadrži svu primljenu e-poštu. I dalje morate da skladištite enkodrianje pored svakog dela čitljivog dela teksta . Razmisli? Pokušaj pretražiti bazu podataka e-pošte, koja mora da pretvara između više kodiranja u letu. Da li to zvuči zabavno? Sada razmislite o mogućnosti višejezičnih dokumenata na kojima su karakteri iz nekokaraktero jezika jedni pored drugih u istom dokumentu. (Savet: programi koji su to pokušali najčešće su koristilii kodove za bekstvo prebacivanje „modova.“ Uf, ti si u ruskom koi8-r režimu, tako da 241 znači A; Uf, sada se govori na grčkom jeziku , znači 241 znači ώ.).) I naravno, takođe ne želite da pretražujem te dokumente. Sada plačite , jer sve što ste mislili da znate o stringovima je pogrešno, i "čist tekst" ne postoji '4.2 Unikod' Unesite unikod 108 Unicode je sistem dizajniran da predstavlja svaki karakter iz svakog jezika. Unicode predstavlja svako slovo, karakter ili ideograf kao 4-bajtni broj. Svaki broj predstavlja jedinstveni znak koji se koristi u bar u jednom od svetskih jezika. (Ne koriste se svi brojevi, ali njih više od 65535, dakle 2 bajtovi ne bi bili dovoljni.) Znakovi koji se koriste na više jezika uglavnom imaju isti broj, osim ako postoji dobar etimološki razlog da se to tako ne radi. Bez obzira na to, postoji tačno jedan broj po znaku i tačno jedan znak po broju. Svaki broj uvek ima samo jednu stvar; ne postoje „režimi“ koje treba pratiti U + 0041 je uvek „A“, čak i ako jezik nema „A“. То је sjajna ideja. Jedno kodiranje koje će svima njima vladati. Više jezika po dokument. Nema više "prebacivanja režima" za prebacivanje između kodiranja u sred radnje. Očigledno postavlja se jedno pitanje. Četiri bajta? Za svaki pojedini karakter? Izgleda stvarno bahato, posebno za jezike poput engleskog i španskog, kojima je potrebno manje od jednog bajta (256 brojeva) da bi izrazili svaki mogući karakter. Zapravo, rasipa se čak i za jezike zasnovane na ideografima (poput kineskog), kojim nikada treba više od dva bajta po znaku. Postoji Unicode kodiranje koje koristi četiri bajta po znaku. Zove se UTF-32, jer je 32 bita = 4 bajtova. UTF-32 je direktno kodiranje; uzima svaki Unicode znak (4-bajtni broj) i predstavlja znak sa istim brojem. To ima neke prednosti, od kojih je najvažnija možete naći N-ti znak niza u realnom vremenu, jer Nti znak počinje na 4 × Nti bajt. Takođe ima par nedostataka, najočigledniji je da je potrebno četiri bajta da bi se skladištio svaki čudni karakter. Iako postoji puno Unicode karakterа, ispada da većina ljudi nikada ništa neće koristiti izvan prvih 65535. Dakle, postoji još jedno kodiranje Unicode-a, koje se naziva UTF-16 (jer 16 bita = 2 bajta). UTF-16 kodira svaki znak od 0–65535 kao dva bajta, a zatim koristi neke prljave hakove ako vam stvarno trebaju da predstavljaju retko korišćene „astralne ravni“ Unicode znakovi koji prelaze 65535. Najočitija prednost: UTF-16 je dvostruko manji od UTF-32, jer je za svaki znak potreban samo dva bajta umesto četiri bajta . I još uvek lako možete pronaći N-ti karakter stringa u stalnom vremenu, ako pretpostavite da niz ne sadrži bilo koji astralni ravni, što je a dobra pretpostavka do momenta kada nije dobra. Ali postoje i očigledni nedostaci i za UTF-32 i za UTF-16. Različiti računarski sistemi skladište pojedinačne bajtove na različite načine. To znači da bi znak U + 4E2D bi mogao da bude sačuvan u UTF-16 4E 2D ili 2D 4E, zavisno od toga da li je sistem big-endian ili mali-endian. (Za UTF-32 postoje čak još više mogućih rasporeda bajtova.) Sve dok dokumenti nikada ne napuste računar, vi ste sigurni - različite aplikacije na istom računaru upotrebljavaće isti poredak bajta. Ali onog trenutka kada želite da prenesete dokument između sistema, npr na mrežu, treba vam način da naznačite u kom su redosledu su skladišteni vaši bajtovi. U suprotnom, prijemni sistem nema načina da zna da li dvobajtni niz 4E 2D znači U + 4E2D ili U + 2D4E. Da biste rešili ovaj problem, višebajtni kodovi Unicode definišu kao „Byte order Mark“, što je poseban karakter koji se ne može štampati i koji možete da dodate na početku svog dokumenta kako biste naznačili koji je nalog vaš bajtovi su unutra. Za UTF-16, marka za poredak bajtova je U + FEFF. Ako dobijete dokument UTF-16 koji počinje sa bajtovi FF FE, znate da je redosled bajta jednosmerno; ako započne sa FE FF, znate da je redosled bajtova obrnut. Ipak, UTF-16 nije baš idealan, pogotovo ako imate posla sa mnogo ASCII znakova. Ako razmislite čak i kineska veb stranica sadrži puno ASCII znakova - svih elemenata i atributa okružujući kineske znakove za ispis. Lepo je kad možeš pronaći n-ti karakter u realnom vremenu, ali još uvek postoji težak problem tih karakterova iz astralne ravni, što znači da ne možete da garantujete da je svaki znak tačno dva bajta, tako da stvarno ne možete da pronađete N-ti znak u stalnom vremenu osim ako zadržavate zaseban indeks. A sigurno ima puno ASCII teksta na ovom svetu ... Drugi ljudi su razmišljali o tomei našli su rešenje: UTF-8 110 UTF-8 je sistem kodiranja promenljive dužine za Unicode. Odnosno, različiti karakteri zauzimaju različit broj bajtova. Za ASCII znakove (A-Z i c.) UTF -8 koristi se samo jedan bajt po znaku. U stvari, koriste se potpuno isti bajtovi; prvih 128 znakova (0–127) u UTF -8 se ne razlikuju od ASCII. „Produženi Latino ”znakovi poput n i o na kraju zauzimaju dva bajta. (Bajtovi nisu samo tačka koda kao što su bili u UTF-16; uključeno je nekoliko ozbiljnih zavrzlama.) Kineski znakovi poput 中 na kraju zauzimaju tri bajta. Retko korišteni karakteri „astralne ravni“ imaju četiri bajta. Nedostaci: zato što svaki znak može imati različit broj bajtova, pronalaženje N-tog znaka je O (N) operacija - duži string, duže traje period da bi se pronašao određeni znak. Takođe, postoji zavrzlama koji su potrebni za kodiranje znakova u bajtove i dekodiranje bajtova u znakove. Prednosti: super efikasno kodiranje uobičajenih ASCII znakova.ne manje loše od UTF-16 za produženi latinski jezik karaktera i Bolje od UTF-32 za kineske znakove. Takođe (i moraćete da mi verujete zbog toga, jer Neću da vam objašnjavam matematiku), zbog prirode zavrzlama,ne postoje problemi rasporeda bajtova. Dokument kodiran u UTF -8 koristi isti raspored bajtova na bilo kojem računaru. '4.3. Zaranjanje' U Pytonu 3, svi nizovi su sekvence Unicode znakova. Ne postoji stvar kao što je Python string kodiran u UTF -8 ili Python string kodiranom kao CP-1252. „Da li je ovaj string UTF -8?“ Je neispravno pitanje. UTF -8 je način kodiranja znakova kao niz bajtova. Ako želite da uzmete niz i pretvorite ga u sekvencu bajtova u određenom kodiranju znakova, Python 3 vam može pomoći u tome. Ako želite da uzmete sekvencu bajtova i pretvorite ga u string, Python 3 vam takođe može pomoći u tome. Bajtovi nisu karakteri; bajtovi su bajtovi. Karakteri su apstrakcija. String je sekvenca tih apstrakcija. 111 >>> s = '深入 Python' ① >>> len(s) ② 9 >>> s0 ③ '深' >>> s + ' 3' ④ '深入 Python 3' 1. Da biste stvorili niz, zatvorite ga u navodnicima. Nizovi Python-a mogu se definisati jednimnavodnokom (') ili dvostrukim navodnikom ("). 2. Ugrađena funkcija len () vraća dužinu niza, tj. Broj znakova. Ovo je isto funkciju koju koristite za pronalaženje dužine liste, tuplea, seta ili rečnika (dictionary). Niz je poput tuplea znakova. 3. Baš kao i uklanjanje pojedinačnih stavki sa liste, pojedinačni likovi se mogu izvući iz niza koristeći indeks notaciju. 4. Baš kao i liste, možete povezati nizove pomoću operatora +. '4.4. Formatiranje Stringova' Stringovi mogu da se definišu sa jednim ili dva dupla apostrofa SUFFIXES = {1000: 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', ① 1024: 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'} def approximate_size(size, a_kilobyte_is_1024_bytes=True): Convert a file size to human-readable form. ② Keyword arguments: size -- file size in bytes a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024 if False, use multiples of 1000 Returns: string ' ③ if size < 0: raise ValueError('number must be non-negative') ④ multiple = 1024 if a_kilobyte_is_1024_bytes else 1000 for suffix in SUFFIXESmultiple: size /= multiple if size < multiple: return '{0:.1f} {1}'.format(size, suffix) ⑤ raise ValueError('number too large') 1. 'KB', 'MB', 'GB' ... to su stringovi 2. Funkcionalne docstringovi su stringovi. Ovaj docstring obuhvata više redova, pa koristi apostrofe u tri reda za početak i završi stringova 3. Ovi apostrofi u tri reda završavaju docstring. 4. Postoji još jedan string, koji se kao izuzetak prenosi korisniku kao čitljiva poruka . 5. Postoji ... hej, sta je dodjavola to? Python 3 podržava pretvaranja formatiranja vrednosti u stringove. Iako ovo može da uključuje veoma komplikovane izraze, najosnovnija upotreba je umetanje vrednosti u niz sa jednim rezerviranim mestom. 114 >>> username = 'mark' >>> password = 'PapayaWhip' ① >>> "{0}'s password is {1}".format(username, password) ② "mark's password is PapayaWhip" 1. Ne, moja lozinka zaista nije PapayaVhip. 2. Ovde se puno toga događa. Prvo, to je poziv metode na literalnom stringu. Stringovi su objekti, a objekti imaju metode. Drugo, ceo izraz vrednuje niz. Treće, {0} i {1} su rezervna polja, koja zamenjuju se argumentima prosleđenim metodi format (). '4.4.1. Složena polja imena Prethodni primer prikazuje najjednostavniji slučaj, gde su zamenska polja jednostavan celi brojevi. Integer zamenska polja tretiraju se kao pozicioni indeksi u listi argumenata metode format (). To znači da se {0} zamenjuje prvim argumentom (korisničko ime u ovom slučaju), {1} se zamenjuje drugim argumentom (lozinka) i c. Možete imati onoliko indeksa pozicije koliko imate argumenata, a možete i njih onoliko argumenata koliko želite. Ali polja za zamenu su mnogo moćnija od toga. >>> import humansize >>> si_suffixes = humansize.SUFFIXES1000 ① >>> si_suffixes 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' >>> '1000{00} = 1{01}'.format(si_suffixes) ② '1000KB = 1MB' 1. Umesto da pozovete bilo koju funkciju u humansize modulu, samo ste ugrabili jednu od podataka koji definiše: popis sufiksa „SI“ (powers-of-1000). 2. Ovo izgleda komplikovano, ali nije. {0} će se odnositi na prvi argument prosleđen metodi format (), si_suffikes. Ali si_suffikes je lista. Dakle, {0 0} se odnosi na prvu stavku liste koja je prvi argument prosleđen metodi format (): 'KB'. U međuvremenu, {0 1} se odnosi na drugu stavku iste liste: 'MB'. Sve izvan vitičaste zagrade - uključujući 1000, znak jednake i razmake - ostaje netaknuto. Krajnji rezultat je string '1000KB = 1MB'. 115 {0} je zamenjen prvo sa format () argumentom.{1} je zamenjen sa drugim. Ono što ovaj primer pokazuje jeste da format specifikator može da pristupa stavkama i svojstvima strukture podataka koristeći sintaksu Python. To se naziva složenim imenima polja. Navedena složena polja imena rade: • Donošenje liste i pristup listi stavki po indeksu (kao u prethodnom primeru) • Donošenje rečnika i pristup vrednostima rečnik po ključu • Pronalazak modula i pristup njegovim promenljivim i funkcije po imenu • Prenošenje instancije klase i pristup njenim svojstvima i metodama po imenu • Bilo koja kombinacija gore navedenog Evo vam primer koji kombinuje sve gore navedeno: >>> import humansize >>> import sys >>> '1MB = 1000{0.moduleshumansize.SUFFIXES10000}'.format(sys) '1MB = 1000KB' Evo kako to funkcioniše: • Sis modul sadrži informacije o trenutno pokrenutoj instanci Pythona. Pošto ste ga upravo uvezli, možete proslediti sam sys modul kao argument metodi (() formatu). Dakle, polje za zamenu {0} odnosi se na sys modul. • sys.modules je rečnik svih modula koji su uvezeni u ovoj Python instanci. Ključevi su modul se imenuju kao nizovi; vrednosti su sami modulski objekti. Dakle, polje za zamenu {0.modules} odnosi se na rečnik uvezenih modula. 116 • sys.modules 'humansize' je humansize modul koji ste upravo uveli. Polje za zamenu {0.modules se odnosi na humansize modul. Ovde imajte na umu malu razliku u sintaksi. U stvarnom Python kodu, ključevi sys.modules rečnika su stringovi; da biste ih uputili, trebate da stavite apostrofe oko naziva modula (npr. 'humansize'). Ali u polju za zamenu preskočite navodnike oko imena ključnog rečnika (npr. humansize). Da citiram PEP 3101: Advanced String Formatting, „Pravila za raščlanjivanje ključa za stavku je vrlo jednostavan. Ako počinje sa cifrom, tada se tretira kao broj, inače se koristi kao string." • sys.modules ['humansize' .SUFFIXES je rečnik definisan na vrhu humansize modula. polje za zamenu {0. modules humansize .SUFFIXES} se odnosi na taj rečnik. • sys.modules 'humansize] SUFFIXES 1000 je lista sufiksa SI: KB ',' MB ',' GB ',' TB ',' PB ',' EB ', 'ZB', 'IB'. Dakle, polje za zamenu {0.modules humize .SUFFIXES 1000} se odnosi na tu listu. • sys.modules 'humansize'. SUFFIXES 1000 0 je prva stavka na listi sufiksa SI: 'KB'. Stoga kompletno polje za zamenu {0. modules humansize .SUFFIXES 1000 0} se zamenjuje dvoznačnim stringom KB KRAJ